package win.larryzeal.spring.theme.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.converter.BufferedImageHttpMessageConverter;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.ResourceBundleThemeSource;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.theme.CookieThemeResolver;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * Created by 张少昆 on 2017/8/25 0025.
 */
@Configuration
@EnableWebMvc
@ComponentScan(
		basePackages = {"win.larryzeal.spring.theme.web.controller"},
		includeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, value = {Controller.class} )
)
public class MvcConfig extends WebMvcConfigurerAdapter {
	/*
	 * Configure ContentNegotiationManager
	 * <mvc:annotation-driven content-negotiation-manager="configurer">
	 */
	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer){
		configurer
				// 设置为 true 以忽略对 Accept Header 的支持
				.ignoreAcceptHeader(false)
				// true：开启扩展名支持；false：关闭支持
				.favorPathExtension(true)
				// 用于开启 /userinfo/123?format=json的支持
				.favorParameter(false)
				.useJaf(false)
				.mediaType("json", MediaType.APPLICATION_JSON_UTF8)
				.mediaType("xml", MediaType.APPLICATION_XML)
				// .mediaType("html", MediaType.TEXT_XML)
				// 当请求 accept 为空时，默认按 defaultContentType 返回
				// 当没有设置 defaultContentType 按 方法的 produces 顺序返回
				.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
	}

	/**
	 * 添加转换器
	 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters){
		converters.addAll(converters());
	}

	/**
	 * 为什么不使用默认的？因为默认的没有使用UTF8编码！且，可能出现一堆ResponseHeader
	 *
	 * @return
	 */
	@Bean
	public List<HttpMessageConverter<?>> converters(){
		List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();

		messageConverters.add(new BufferedImageHttpMessageConverter());
		messageConverters.add(new ByteArrayHttpMessageConverter());             // [application/octet-stream, */*]
		messageConverters.add(new AllEncompassingFormHttpMessageConverter());// [application/x-www-form-urlencoded, multipart/form-data]
		messageConverters.add(new Jaxb2RootElementHttpMessageConverter()); // [application/xml, text/xml, application/*+xml]

		// 避免所有可用字符集回写到response响应头Accept-Charset中
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
		stringHttpMessageConverter.setWriteAcceptCharset(false);
		stringHttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN, MediaType.TEXT_HTML));
		messageConverters.add(stringHttpMessageConverter); // [text/plain, text/html, text/xml]

		MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
		ObjectMapper mapper = new ObjectMapper();
		mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		// 忽略不存在的属性
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		// mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
		mapper.setTimeZone(TimeZone.getDefault());
		mappingJackson2HttpMessageConverter.setObjectMapper(mapper);
		mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8));
		messageConverters.add(mappingJackson2HttpMessageConverter); // [application/json]

		return messageConverters;
	}

	/**
	 * 拦截器
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry){
		// 自定义拦截器 无

		// 本地化拦截器
		LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
		localeChangeInterceptor.setParamName("language");
		registry.addInterceptor(localeChangeInterceptor).addPathPatterns("/**");

		// themeChangeInterceptor
		registry.addInterceptor(themeChangeInterceptor()).addPathPatterns("/**");
	}

	@Bean
	public ViewResolver viewResolver(){
		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
		resolver.setViewClass(JstlView.class);
		resolver.setContentType(MediaType.TEXT_HTML_VALUE);
		resolver.setPrefix("/WEB-INF/views/");
		resolver.setSuffix(".jsp");

		resolver.setOrder(15);
		return resolver;
	}

	/**
	 * SpringMVC 处理上传文件的信息
	 */
	@Bean
	public CommonsMultipartResolver multipartResolver() throws IOException{
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
		multipartResolver.setDefaultEncoding(StandardCharsets.UTF_8.displayName());
		multipartResolver.setUploadTempDir(new FileSystemResource(System.getProperty("java.io.tmpdir")));
		return multipartResolver;
	}

	/**
	 * 基于cookie的本地化资源处理器
	 */
	@Bean
	public CookieLocaleResolver localeResolver(){
		CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
		// cookie 最大时间为 10天
		cookieLocaleResolver.setCookieMaxAge(3600); // an hour
		cookieLocaleResolver.setDefaultTimeZone(TimeZone.getDefault());
		cookieLocaleResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
		return cookieLocaleResolver;
	}

	/**
	 * 静态资源访问(缓存一周)
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry){
		super.addResourceHandlers(registry);
		registry.addResourceHandler("/images/**").addResourceLocations("/images/").setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
		registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
		registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
		registry.addResourceHandler("/common/**").addResourceLocations("/common/").setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
		registry.addResourceHandler("/download/**").addResourceLocations("/download/").setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
		registry.addResourceHandler("/themes/**").addResourceLocations("/themes/").setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
	}


	/**
	 * 主题源
	 *
	 * @return
	 */
	@Bean
	public ThemeSource themeSource(){
		ResourceBundleThemeSource resourceBundleThemeSource = new ResourceBundleThemeSource();
		resourceBundleThemeSource.setBasenamePrefix("theme-");
		return resourceBundleThemeSource;
	}

	/**
	 * 主题拦截器
	 *
	 * @return
	 */
	@Bean
	public ThemeChangeInterceptor themeChangeInterceptor(){
		ThemeChangeInterceptor themeChangeInterceptor = new ThemeChangeInterceptor();
		themeChangeInterceptor.setParamName("theme");
		return themeChangeInterceptor;
	}

	/**
	 * 主题解析器
	 *
	 * @return
	 */
	@Bean
	public ThemeResolver themeResolver(){
		CookieThemeResolver cookieThemeResolver = new CookieThemeResolver();
		cookieThemeResolver.setDefaultThemeName("default");

		return cookieThemeResolver;
	}

//	/**
//	 * Configure TilesConfigurer.
//	 */
//	@Bean
//	public TilesConfigurer tilesConfigurer(){
//		TilesConfigurer tilesConfigurer = new TilesConfigurer();
//		tilesConfigurer.setDefinitions(new String[] {"/WEB-INF/views/**/tiles.xml"});
//		tilesConfigurer.setCheckRefresh(true);
//		return tilesConfigurer;
//	}
//
//	/**
//	 * Configure ViewResolvers to deliver preferred views.
//	 */
//	public void configureViewResolvers(ViewResolverRegistry registry) {
//		TilesViewResolver viewResolver = new TilesViewResolver();
//		registry.viewResolver(viewResolver);
//	}

}
